#include <benchmark/benchmark.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include "util.h"

#define PORT 1500 //端口号 
#define BACKLOG 5

static void Bm_function_socket_server(benchmark::State &state)
{
    struct sockaddr_in serverAddr;
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); //本主机的任意IP地址
    serverAddr.sin_port = htons(PORT);
    bzero(&(serverAddr.sin_zero), 8); //将其他属性置0
    for (auto _ : state)
    {
        int serverFd = socket(AF_INET, SOCK_STREAM, 0);
        if (serverFd == -1) {
            printf("socket failed:%d",errno);
            break;
        }
/*        if (bind(serverFd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr)) < 0) {
            printf("bind error");
            close(serverFd);
            break;
        }
        listen(serverFd, BACKLOG); //开启监听 ，第二个参数是最大监听数

        int clientfd;  //客户端的socket
        int socklen=sizeof(struct sockaddr_in);  // struct sockaddr_in的大小
        struct sockaddr_in clientaddr;  //客户端的地址信息
        clientfd = accept(serverfd, (struct sockaddr*)&clientaddr, (socklen_t*)&socklen);

        // 与客户端通信,接收客户端发过来的报文后, 回复报文加OK
        char strbuffer[1024];
        while(1){
            memset(strbuffer, 0, sizeof(strbuffer));
            if(recv(clientfd, strbuffer, sizeof(strbuffer), 0)<=0) break;
            printf("接收: %s\n",strbuffer);

            strcpy(strbuffer, "OK");

            if(send(clientfd, strbuffer, strlen(strbuffer),0)<=0) break;

            printf("发送:%s\n",strbuffer);
        }
*/
        close(serverFd);
    }
    state.SetBytesProcessed(state.iterations());
}

static void Bm_function_socketpair_sendmsg_recvmsg(benchmark::State &state)
{
    int ret;
    int socks[2];
    struct msghdr msg;
    struct iovec iov[1];
    char send_buf[100] = "it is a test";
    struct msghdr msgr;
    struct iovec iovr[1];
    char recv_buf[100];
 
    for (auto _ : state)
    {
        ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, socks);
        if (ret == -1) {
            printf("socketpair err\n");
            break;   
        }
    
        bzero(&msg, sizeof(msg));
        msg.msg_name = NULL;
        msg.msg_namelen = 0;
        iov[0].iov_base = send_buf;
        iov[0].iov_len = sizeof(send_buf);
        msg.msg_iov = iov;
        msg.msg_iovlen = 1;
    
        ret = sendmsg(socks[1], &msg, 0);
        if(ret == -1 ){
            printf("sendmsg err\n");
            close(socks[0]);
            close(socks[1]);
            break;
        }
    
        bzero(&msg, sizeof(msg));
        msgr.msg_name = NULL;   
        msgr.msg_namelen = 0;
        iovr[0].iov_base = &recv_buf;
        iovr[0].iov_len = sizeof(recv_buf);
        msgr.msg_iov = iovr;
        msgr.msg_iovlen = 1;
        ret = recvmsg(socks[0], &msgr, 0);
        if(ret == -1 ){
            printf("recvmsg err\n");
        }
        close(socks[0]);
        close(socks[1]);
    }
    state.SetBytesProcessed(state.iterations());
}

static void Bm_function_getsockopt(benchmark::State &state)
{
    int optVal;
    socklen_t optLen = sizeof(optVal);
    
    for (auto _ : state)
    {
        int sockFd = socket(AF_INET, SOCK_STREAM, 0);
        if (getsockopt(sockFd, SOL_SOCKET, SO_SNDBUF, &optVal, &optLen) < 0) {
            printf("fail to getsockopt");
        }
        close(sockFd);
    }
    state.SetBytesProcessed(state.iterations());
}

static void Bm_function_setsockopt(benchmark::State &state)
{
    for (auto _ : state)
    {
        int nRecvBuf = 32*1024; // 设置为32K
        int sockFd = socket(AF_INET, SOCK_STREAM, 0);
        if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf, sizeof(int)) < 0) {
            printf("fail to setsockopt");
        }
        close(sockFd);
    }
    state.SetBytesProcessed(state.iterations());
}

MUSL_BENCHMARK(Bm_function_socket_server);
MUSL_BENCHMARK(Bm_function_socketpair_sendmsg_recvmsg);
MUSL_BENCHMARK(Bm_function_getsockopt);
MUSL_BENCHMARK(Bm_function_setsockopt);

